package com.cmic.rcs.emoji.common.aop;

import com.cmic.rcs.emoji.common.UserContext;
import com.cmic.rcs.emoji.entity.dto.UserDto;
import com.cmic.rcs.emoji.util.IpUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

@Slf4j
@Aspect
@Component
/**
 * 日志切面
 */
public class WebLogAspect {

    @Autowired
    private ObjectMapper objectMapper;

    @Pointcut("execution(* com.cmic.rcs.emoji.controller..*.*(..)) ") // 排除 CommonController
    public void pointcut() {
    }


    @Around("pointcut()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        long start = System.currentTimeMillis();
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        HttpServletResponse response = attributes.getResponse();
        UserDto userDto = UserContext.getUserDto();
        try {
            String typeName = joinPoint.getSignature().getDeclaringTypeName();
            String name = joinPoint.getSignature().getName();
            String remoteIP = request.getRemoteAddr();
            String ip = IpUtils.getReal(request);
            String url = request.getRequestURL() + (ObjectUtils.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString());
            String forward = request.getHeader("X-Forwarded-For");
            String method = request.getMethod();
            String agent = request.getHeader("user-agent");
            String body = getPostArg(request, joinPoint.getArgs());
            Object result = joinPoint.proceed();

            log.info("request: {}|{}|{}|{}|{}|{}|{} |{}|{}|{}ms|{}|{}|{}",
                    remoteIP,
                    ip,
                    forward,
                    typeName,
                    name,
                    method,
                    url,
                    agent,
                    response != null ? response.getStatus() : "-",
                    System.currentTimeMillis() - start,
                    userDto != null ? userDto.getUsername() : "未知用户", // 防止 NullPointerException
                    body,
                    result == null ? null : objectMapper.writeValueAsString(result)
            );
            return result;
        } catch (Throwable ex) {
            String typeName = joinPoint.getSignature().getDeclaringTypeName();
            String name = joinPoint.getSignature().getName();
            String remoteIP = request.getRemoteAddr();
            String ip = IpUtils.getReal(request);
            String url = request.getRequestURL() + (ObjectUtils.isEmpty(request.getQueryString()) ? "" : "?" + request.getQueryString());
            String forward = request.getHeader("X-Forwarded-For");
            String method = request.getMethod();
            String agent = request.getHeader("user-agent");
            String body = getPostArg(request, joinPoint.getArgs());
            log.error("request exception: {}|{}|{}|{}|{}|{}|{} |{}|{}|{}ms|{}|{}|{}",
                    remoteIP,
                    ip,
                    forward,
                    typeName,
                    name,
                    method,
                    url,
                    agent,
                    response != null ? response.getStatus() : "-",
                    System.currentTimeMillis() - start,
                    userDto != null ? userDto.getUsername() : "未知用户",
                    body,
                    ex.toString()
            );
            throw ex;
        }
    }

    private String getPostArg(HttpServletRequest request, Object[] args) throws JsonProcessingException {
        StringBuilder bodyBuilder = new StringBuilder();
        String method = request.getMethod();
        if (("POST".equals(method) || "PUT".equals(method)) && args != null) {
//            bodyBuilder.append("[request param:");
            for (Object arg : args) {
                if (arg instanceof HttpServletRequest || arg instanceof HttpServletResponse) {
                    continue;
                }
                if (arg instanceof MultipartFile) {
                    bodyBuilder.append("multipartFile").append(" ");
                    continue;
                }
                // 过滤掉 session 相关对象，避免循环引用
                if (arg instanceof HttpSession ||
                        arg.getClass().getName().contains("Session")) {
                    bodyBuilder.append("{\"message\":\"[Session object ignored for logging]\"} ");
                    continue;
                }
                bodyBuilder.append(objectMapper.writeValueAsString(arg)).append(" ");
            }
//            bodyBuilder.append("]");
        }
        return bodyBuilder.toString();
    }
}
